
unit IfxDataSetTests;


interface

uses
  DB,
  LXDataSetImpl, 
  IfxConnection,
  IfxCustomDataSet,
  IfxDataSet,
  IfxQuery,
  IfxStoredProc,
  IfxTable,
  TestFrameWork;

  
type

{ TIfxCommonTests }

  TIfxCommonTests = class(TTestCase)
  private
    FConnection: TIfxConnection;
    FDataSet: TIfxCustomDataSet;
    FAssertFlag: Boolean;

  protected
    procedure SetUp; override;
    procedure TearDown; override;

    function CreateDataSet: TIfxCustomDataSet; virtual; abstract;
    procedure SetCustomerCommand; virtual; abstract;
    procedure SetCustomerEmptyCommand; virtual; abstract;
    procedure SetCatalogCommand; virtual; abstract;
    procedure SetCatalogEmptyCommand; virtual; abstract;

    procedure AfterDataSetConstruction(Sender: TObject);
    procedure BeforeDataSetDestruction(Sender: TObject);

    property DataSet: TIfxCustomDataSet read FDataSet;

  published
    // Test methods
    procedure TestCreate;
    procedure TestDestroy;
    procedure TestAfterConstruction;
    procedure TestBeforeDestruction;
    procedure TestPrepare;
    procedure TestUnprepare;
    procedure TestGetCurrentRecord;
    procedure TestGetFieldData;
    procedure TestGetBlobFieldData;
    procedure TestCreateBlobStream;
    procedure TestFetchAll;
    procedure TestApplyUpdates;
    procedure TestCommitUpdates;
    procedure TestCancelUpdates;
    procedure TestRevertRecord;
    procedure TestIsSequenced;
    procedure TestUpdateStatus;
    procedure TestBookmarkValid;
    procedure TestCompareBookmarks;
    procedure TestLocate;
    procedure TestLookup;
    procedure TestUnidirectinal;
    procedure TestRefreshWithTrimStrings;
  end;


{ TIfxDataSetTests }

  TIfxDataSetTests = class(TIfxCommonTests)
  protected
    function CreateDataSet: TIfxCustomDataSet; override;
    procedure SetCustomerCommand; override;
    procedure SetCustomerEmptyCommand; override;
    procedure SetCatalogCommand; override;
    procedure SetCatalogEmptyCommand; override;
  published
    procedure TestParseMacroSQL;
  end;


{ TIfxQueryTests }

  TIfxQueryTests = class(TIfxCommonTests)
  protected
    function CreateDataSet: TIfxCustomDataSet; override;
    procedure SetCustomerCommand; override;
    procedure SetCustomerEmptyCommand; override;
    procedure SetCatalogCommand; override;
    procedure SetCatalogEmptyCommand; override;
  published
    procedure TestParseMacroSQL;
  end;


{ TIfxStoredProcTestsIfx }

  TIfxStoredProcTestsIfx = class(TIfxCommonTests)
  protected
    function CreateDataSet: TIfxCustomDataSet; override;
    procedure SetCustomerCommand; override;
    procedure SetCustomerEmptyCommand; override;
    procedure SetCatalogCommand; override;
    procedure SetCatalogEmptyCommand; override;
  end;


{ TIfxTableTestsIfx }

  TIfxTableTestsIfx = class(TIfxCommonTests)
  private
    procedure IgnoreRecord(DataSet: TDataSet; var Accept: Boolean);
  protected
    function CreateDataSet: TIfxCustomDataSet; override;
    procedure SetCustomerCommand; override;
    procedure SetCustomerEmptyCommand; override;
    procedure SetCatalogCommand; override;
    procedure SetCatalogEmptyCommand; override;
  end;


implementation

uses SysUtils, Variants, Classes, LXMacroSQL, Ifx;


{ TIfxCommonTests }

procedure TIfxCommonTests.SetUp;
begin
  inherited;
  FConnection := TIfxConnection.Create(nil);
  FConnection.Params.Values[szDATABASE] := 'stores7';
  FConnection.PoolOptions.Enabled := True;
  FDataSet := CreateDataSet;
  FDataSet.Connection := FConnection;
  SetCustomerCommand;
  FConnection.Execute('delete from customer where lname like ''Test record %''');
end;

procedure TIfxCommonTests.TearDown;
begin
  inherited;
  FreeAndNil(FConnection);
  FreeAndNil(FDataSet);
end;

procedure TIfxCommonTests.AfterDataSetConstruction(Sender: TObject);
begin
  FAssertFlag := True;
end;

procedure TIfxCommonTests.TestAfterConstruction;
begin
  with TIDACEvents.Create(nil) do
    try
      OnObjectCreate := AfterDataSetConstruction;
      CreateDataSet.Free;
      Assert(FAssertFlag);
    finally
      Free;
    end;
end;

procedure TIfxCommonTests.BeforeDataSetDestruction(Sender: TObject);
begin
  FAssertFlag := True;
end;

procedure TIfxCommonTests.TestBeforeDestruction;
begin
  with TIDACEvents.Create(nil) do
    try
      OnObjectCreate := AfterDataSetConstruction;
      CreateDataSet.Free;
      Assert(FAssertFlag);
    finally
      Free;
    end;
end;

procedure TIfxCommonTests.TestCreate;
begin
  Assert(FDataSet <> nil);
end;

procedure TIfxCommonTests.TestDestroy;
begin
  FreeAndNil(FDataSet);
end;

procedure TIfxCommonTests.TestPrepare;
begin
  // !!! FDataSet.Prepared := True;
end;

procedure TIfxCommonTests.TestUnprepare;
begin
  // !!! FDataSet.Unprepare;
  // !!! FDataSet.Prepare;
  // !!! FDataSet.Unprepare;
end;

procedure TIfxCommonTests.TestGetCurrentRecord;
begin
  Assert(not FDataSet.GetCurrentRecord(nil));
  FDataSet.Open;
  Assert(FDataSet.GetCurrentRecord(nil));
end;

procedure TIfxCommonTests.TestGetFieldData;
var
  Buffer: array of Byte;
begin
  FDataSet.Open;
  SetLength(Buffer, FDataSet.Fields[0].DataSize);
  FDataSet.Close;
  SetCustomerEmptyCommand;
  FDataSet.Open;
  Assert(not FDataSet.GetFieldData(FDataSet.Fields[0], Pointer(Buffer)));
end;

procedure TIfxCommonTests.TestGetBlobFieldData;
var
  Buffer: TBlobByteData;
begin
  FDataSet.Open;
  try
    FDataSet.GetBlobFieldData(4, Buffer);
    Fail('Cannot get blob data for a non blob field');
  except
    on EDatabaseError do;
  end;
  FDataSet.Close;
  SetCatalogCommand;
  FDataSet.Open;
  Assert(FDataSet.GetBlobFieldData(
    FDataSet.FieldByName('cat_descr').FieldNo, Buffer) > 0);
  FDataSet.Close;
  SetCatalogEmptyCommand;
  FDataSet.Open;
  Assert(FDataSet.GetBlobFieldData(
    FDataSet.FieldByName('cat_descr').FieldNo, Buffer) = 0);
end;

procedure TIfxCommonTests.TestCreateBlobStream;
var
  Stream: TStream;
begin
  FDataSet.Open;
  try
    FDataSet.CreateBlobStream(FDataSet.Fields[0], bmRead).Free;
    Fail('Cannot create blob stream for a non blob field');
  except
    on EDatabaseError do;
  end;
  FDataSet.Close;
  SetCatalogCommand;
  FDataSet.Open;
  Stream := FDataSet.CreateBlobStream(FDataSet.FieldByName('cat_descr'), bmRead);
  try
    Assert((Stream <> nil) and (Stream.Size <> 0));
  finally
    FreeAndNil(Stream);
  end;
  FDataSet.Close;
  SetCatalogEmptyCommand;
  FDataSet.Open;
  Stream := FDataSet.CreateBlobStream(FDataSet.FieldByName('cat_descr'), bmRead);
  try
    Assert((Stream <> nil) and (Stream.Size = 0));
  finally
    FreeAndNil(Stream);
  end;
end;

procedure TIfxCommonTests.TestFetchAll;
begin
  FDataSet.Open;
  FDataSet.FetchAll;
end;

procedure TIfxCommonTests.TestApplyUpdates;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;
  FDataSet.ApplyUpdates;

  FDataSet.Close;
  FDataSet.Open;
  Assert(FDataSet.Locate('lname', 'Test record 1', []));
  FDataSet.Edit;
  FDataSet.FieldByName('lname').AsString := 'Test record 3';
  FDataSet.Post;
  Assert(FDataSet.Locate('lname', 'Test record 2', []));
  FDataSet.Delete;
  FConnection.ApplyUpdates([FDataSet]);

  FDataSet.Close;
  FDataSet.Open;
  Assert(not FDataSet.Locate('lname', 'Test record 1', []));
  Assert(not FDataSet.Locate('lname', 'Test record 2', []));
  Assert(FDataSet.Locate('lname', 'Test record 3', []));
end;

procedure TIfxCommonTests.TestCommitUpdates;
begin
  FDataSet.CachedUpdates := True;
  FDataSet.AutoCommitUpdates := False;

  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;
  
  IProviderSupport(FDataSet).PSStartTransaction;
  try
    FDataSet.ApplyUpdates;
  finally
    IProviderSupport(FDataSet).PSEndTransaction(False);
  end;

  FDataSet.ApplyUpdates;
  FDataSet.CommitUpdates;
  FDataSet.ApplyUpdates;

  FDataSet.Close;
  FDataSet.Open;
  Assert(FDataSet.Locate('lname', 'Test record 1', []));
  Assert(not FDataSet.LocateNext('lname', 'Test record 1', []));
  Assert(FDataSet.Locate('lname', 'Test record 2', []));
  Assert(not FDataSet.LocateNext('lname', 'Test record 2', []));
end;

procedure TIfxCommonTests.TestCancelUpdates;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;

  FDataSet.Last;
  Assert(FDataSet.Locate('lname', 'Test record 1', []));
  Assert(FDataSet.Locate('lname', 'Test record 2', []));

  FDataSet.CancelUpdates;

  FDataSet.Last;
  Assert(not FDataSet.Locate('lname', 'Test record 1', []));
  Assert(not FDataSet.Locate('lname', 'Test record 2', []));
end;

procedure TIfxCommonTests.TestRevertRecord;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;

  FDataSet.Last;
  Assert(FDataSet.Locate('lname', 'Test record 1', []));

  FDataSet.RevertRecord;

  FDataSet.Last;
  Assert(not FDataSet.Locate('lname', 'Test record 1', []));
end;

procedure TIfxCommonTests.TestIsSequenced;
begin
  FDataSet.Open;
  FDataSet.FetchAll;
  Assert(FDataSet.IsSequenced);
end;

procedure TIfxCommonTests.TestUpdateStatus;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;
  FDataSet.Edit;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 0;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;

  FDataSet.Last;
  Assert(FDataSet.Locate('lname', 'Test record 1', []));
  Assert(FDataSet.UpdateStatus = usModified);
  Assert(FDataSet.Locate('lname', 'Test record 2', []));
  Assert(FDataSet.UpdateStatus = usInserted);

  FDataSet.CancelUpdates;
end;

procedure TIfxCommonTests.TestBookmarkValid;
var
  P: Pointer;
begin
  Assert(not FDataSet.BookmarkValid(nil));
  FDataSet.Open;
  P := FDataSet.GetBookmark;
  try
    Assert(FDataSet.BookmarkValid(P));
    Assert(not FDataSet.BookmarkValid(PChar(P) + 1));
  finally
    FDataSet.FreeBookmark(P);
  end;
end;

procedure TIfxCommonTests.TestCompareBookmarks;
var
  P1, P2: Pointer;
begin
  Assert(FDataSet.CompareBookmarks(nil, nil) = 0);
  FDataSet.Open;
  P1 := FDataSet.GetBookmark;
  FDataSet.Next;
  P2 := FDataSet.GetBookmark;
  try
    Assert(FDataSet.CompareBookmarks(P1, P1) = 0);
    Assert(FDataSet.CompareBookmarks(P2, P1) <> 0);
  finally
    FDataSet.FreeBookmark(P1);
    FDataSet.FreeBookmark(P2);
  end;
end;

procedure TIfxCommonTests.TestLocate;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;

  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 1;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;

  FDataSet.Last;

  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 2;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;

  FDataSet.Next;

  Assert(FDataSet.Locate('customer_num', 2, []));
  Assert(FDataSet.Locate('customer_num', '2', []));
  Assert(FDataSet.Locate('customer_num', '002', []));
  Assert(FDataSet.Locate('customer_num', '  2', []));

  Assert(FDataSet.Locate('customer_num', 1, []));
  Assert(FDataSet.Locate('customer_num', '1', []));
  Assert(FDataSet.Locate('customer_num', '001', []));
  Assert(FDataSet.Locate('customer_num', '  1', []));

  Assert(FDataSet.Locate('lname', 'Test record 2', []));
  Assert(FDataSet.Locate('lname', 'Test record 1', []));

  Assert(FDataSet.Locate('customer_num;lname',
    VarArrayOf([2, 'Test record 2']), []));
  Assert(FDataSet.Locate('customer_num;lname',
    VarArrayOf([1, 'Test record 1']), []));

  Assert(not FDataSet.Locate('lname', 'Test RECORD 2', []));
  Assert(FDataSet.Locate('lname', 'Test RECORD 2', [loCaseInsensitive]));
  Assert(not FDataSet.Locate('lname', 'TEST record 1', []));
  Assert(FDataSet.Locate('lname', 'TEST record 1', [loCaseInsensitive]));

  Assert(not FDataSet.Locate('city;lname',
    VarArrayOf([Null, 'Test RECORD 1']), [loCaseInsensitive]));

  Assert(FDataSet.Locate('lname', 'Test RECORD', [loCaseInsensitive, loPartialKey]));
  Assert(FDataSet.LocateNext('lname', 'Test RECORD', [loCaseInsensitive, loPartialKey]));
  Assert(not FDataSet.LocateNext('lname', 'Test RECORD', [loCaseInsensitive, loPartialKey]));

  FDataSet.CancelUpdates;
end;

procedure TIfxCommonTests.TestLookup;
begin
  FDataSet.CachedUpdates := True;

  FDataSet.Open;

  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 1;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;

  FDataSet.Last;

  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 2;
  FDataSet.FieldByName('lname').AsString := 'Test record 2';
  FDataSet.Post;

  FDataSet.Next;

  Assert(FDataSet.Lookup('customer_num', 1, 'lname') = 'Test record 1');
  Assert(FDataSet.Lookup('customer_num', 2, 'lname') = 'Test record 2');

  Assert(FDataSet.Lookup('lname', 'Test record 1', 'customer_num') = 1);
  Assert(FDataSet.Lookup('lname', 'Test record 2', 'customer_num') = 2);

  FDataSet.CancelUpdates;
end;

procedure TIfxCommonTests.TestUnidirectinal;
begin
  FDataSet.CachedUpdates := True;
  FDataSet.UniDirectional := True;
  ExpectedException := EDatabaseError;
  FDataSet.Insert;
end;

procedure TIfxCommonTests.TestRefreshWithTrimStrings;
begin
  FDataSet.RecordRefreshMode := rmInserted;

  FDataSet.TrimStrings := True;
  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 999;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  Assert(FDataSet.FieldByName('lname').AsString = 'Test record 1');
  FDataSet.Close;

  FDataSet.TrimStrings := False;
  FDataSet.Open;
  FDataSet.Insert;
  FDataSet.FieldByName('customer_num').AsInteger := 1000;
  FDataSet.FieldByName('lname').AsString := 'Test record 1';
  FDataSet.Post;
  Assert(FDataSet.FieldByName('lname').AsString = 'Test record 1  ');
  FDataSet.Close;
end;


{ TIfxDataSetTests }

function TIfxDataSetTests.CreateDataSet: TIfxCustomDataSet;
begin
  Result := TIfxDataSet.Create(nil);
end;

procedure TIfxDataSetTests.SetCustomerCommand;
begin
  TIfxDataSet(DataSet).SelectSQL.Text := 'select * from customer';
end;

procedure TIfxDataSetTests.SetCustomerEmptyCommand;
begin
  TIfxDataSet(DataSet).SelectSQL.Text := 'select * from customer where 1=0';
end;

procedure TIfxDataSetTests.SetCatalogCommand;
begin
  TIfxDataSet(DataSet).SelectSQL.Text := 'select * from catalog';
end;

procedure TIfxDataSetTests.SetCatalogEmptyCommand;
begin
  TIfxDataSet(DataSet).SelectSQL.Text := 'select * from catalog where 1=0';
end;

procedure TIfxDataSetTests.TestParseMacroSQL;
begin
  TIfxDataSet(DataSet).ParseMacroSQL;
  TIfxDataSet(DataSet).SelectSQL.Text := '#ifdef';
  try
    TIfxDataSet(DataSet).ParseMacroSQL;
    Fail('Here must be ELXMacroSQLError');
  except
    on ELXMacroSQLError do;
  end;
end;


{ TIfxQueryTests }

function TIfxQueryTests.CreateDataSet: TIfxCustomDataSet;
begin
  Result := TIfxQuery.Create(nil);
end;

procedure TIfxQueryTests.SetCustomerCommand;
begin
  TIfxQuery(DataSet).SQL.Text := 'select * from customer';
end;

procedure TIfxQueryTests.SetCustomerEmptyCommand;
begin
  TIfxQuery(DataSet).SQL.Text := 'select * from customer where 1=0';
end;

procedure TIfxQueryTests.SetCatalogCommand;
begin
  TIfxQuery(DataSet).SQL.Text := 'select * from catalog';
end;

procedure TIfxQueryTests.SetCatalogEmptyCommand;
begin
  TIfxQuery(DataSet).SQL.Text := 'select * from catalog where 1=0';
end;

//!!!procedure TIfxQueryTests.TestPrepareStatement;
//begin
//  DataSet.SQLConnection.Open;
//  TIfxQuery(DataSet).PrepareStatement;
//  TIfxQuery(DataSet).SQL.Text := '#ifdef';
//  try
//    TIfxQuery(DataSet).PrepareStatement;
//    Fail('Here must be ELXMacroSQLError');
//  except
//    on ELXMacroSQLError do;
//  end;
//end;

procedure TIfxQueryTests.TestParseMacroSQL;
begin
  TIfxQuery(DataSet).ParseMacroSQL;
  TIfxQuery(DataSet).SQL.Text := '#ifdef';
  try
    TIfxQuery(DataSet).ParseMacroSQL;
    Fail('Here must be ELXMacroSQLError');
  except
    on ELXMacroSQLError do;
  end;
end;


{ TIfxStoredProcTestsIfx }

function TIfxStoredProcTestsIfx.CreateDataSet: TIfxCustomDataSet;
begin
  Result := TIfxStoredProc.Create(nil);
end;

procedure TIfxStoredProcTestsIfx.SetCustomerCommand;
begin
  TIfxStoredProc(DataSet).StoredProcName := 'all_customers';
end;

procedure TIfxStoredProcTestsIfx.SetCustomerEmptyCommand;
begin
  TIfxStoredProc(DataSet).StoredProcName := 'all_customers';
end;

procedure TIfxStoredProcTestsIfx.SetCatalogCommand;
begin
  TIfxStoredProc(DataSet).StoredProcName := 'all_customers';
end;

procedure TIfxStoredProcTestsIfx.SetCatalogEmptyCommand;
begin
  TIfxStoredProc(DataSet).StoredProcName := 'all_customers';
end;


{ TIfxTableTestsIfx }

procedure TIfxTableTestsIfx.IgnoreRecord(DataSet: TDataSet; var Accept: Boolean);
begin
  Accept := False;
end;

function TIfxTableTestsIfx.CreateDataSet: TIfxCustomDataSet;
begin
  Result := TIfxTable.Create(nil);
  Result.OnFilterRecord := IgnoreRecord;
end;

procedure TIfxTableTestsIfx.SetCustomerCommand;
begin
  TIfxTable(DataSet).TableName := 'customer';
  TIfxTable(DataSet).Filtered := False;
end;

procedure TIfxTableTestsIfx.SetCustomerEmptyCommand;
begin
  TIfxTable(DataSet).TableName := 'customer';
  TIfxTable(DataSet).Filtered := True;
end;

procedure TIfxTableTestsIfx.SetCatalogCommand;
begin
  TIfxTable(DataSet).TableName := 'catalog';
  TIfxTable(DataSet).Filtered := False;
end;

procedure TIfxTableTestsIfx.SetCatalogEmptyCommand;
begin
  TIfxTable(DataSet).TableName := 'catalog';
  TIfxTable(DataSet).Filtered := True;
end;


initialization

  TestFramework.RegisterTest('IfxDataSetTests Suite',
    TIfxDataSetTests.Suite);
  TestFramework.RegisterTest('IfxQueryTests Suite',
    TIfxQueryTests.Suite);
  //TestFramework.RegisterTest('IfxStoredProcTests Suite',
  //  TIfxStoredProcTestsIfx.Suite);
  TestFramework.RegisterTest('IfxTableTests Suite',
    TIfxTableTestsIfx.Suite);

end.
